﻿using System.Threading;
using System.Timers;
using Timer = System.Timers.Timer;

namespace System
{
    /// <summary>
    /// TimeOutHelper超时帮助类，和该方法
    /// var tempTask = Task.Factory.StartNew(() =>
    /// {
    ///     等待过程中代码
    /// });
    /// tempTask.Wait(3000);
    /// 功能一致,适合回调方式使用
    /// </summary>
    public class TimeOutHelper
    {
        #region 成员
        /// <summary>
        /// 阻塞对象
        /// </summary>
        private AutoResetEvent AutoReset;

        /// <summary>
        /// 超时计时器
        /// </summary>
        private Timer TimerTimeOut;
        #endregion

        #region 属性

        /// <summary>
        /// Id
        /// </summary>
        public string Id = Guid.NewGuid().ToString();

        /// <summary>
        /// 错误码
        /// </summary>
        public int ErrorCode { get; private set; }

        /// <summary>
        /// 错误信息
        /// </summary>
        public string ErrorMessage { get; private set; }

        /// <summary>
        /// 是否等待中
        /// </summary>
        private bool IsWaiting;

        /// <summary>
        /// 是否结束
        /// </summary>
        private bool IsClosed;

        /// <summary>
        /// 是否超时
        /// </summary>
        private bool IsTimeout;

        #endregion

        #region 构造
        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="timeout">时间(毫秒)</param>
        public TimeOutHelper(double? timeout = null)
        {
            AutoReset = new AutoResetEvent(false);
            if (timeout == null)
            {
                timeout = TimeSpan.FromSeconds(GetTimeOut()).TotalMilliseconds;
            }
            TimerTimeOut = new Timer(timeout.Value);
            TimerTimeOut.AutoReset = false;
            TimerTimeOut.Elapsed += _timer_Elapsed;
        }
        #endregion

        #region 方法
        /// <summary>
        /// 获取默认超时时间
        /// </summary>
        /// <returns></returns>
        private static double GetTimeOut()
        {
            double timeout = ConfigHelper.GetConfig("ServerTimeOut").ToDouble(3);
            return timeout > 3 ? 3 : timeout;
        }

        /// <summary>
        /// 计时器执行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            try
            {
                TimerTimeOut.Stop();
                IsTimeout = true;
            }
            finally
            {
                ErrorCode = ErrorCodes.Code_TIMEOUT;
                ErrorMessage = ErrorHelper.GetError(ErrorCode);
                WaitEnd();
            }
        }

        /// <summary>
        /// 等待
        /// </summary>
        public void Wait()
        {
            if (IsWaiting || IsClosed)
                return;
            IsWaiting = true;
            TimerTimeOut.Start();
            AutoReset.WaitOne();
        }

        /// <summary>
        /// 停止超时计时器
        /// </summary>
        public void StopTime()
        {
            TimerTimeOut.Stop();
        }

        /// <summary>
        /// 超时计时器重新计时
        /// </summary>
        public void ResetTime()
        {
            TimerTimeOut.Stop();
            TimerTimeOut.Start();
        }

        /// <summary>
        /// 结束
        /// </summary>
        public void WaitEnd()
        {
            if (IsClosed)
                return;
            TimerTimeOut.Stop();
            TimerTimeOut.Close();
            AutoReset.Set();
            AutoReset.Close();
            IsClosed = true;
            IsWaiting = false;
        } 
        #endregion
    }
}
